package com.xxr.mom.ci.charging.interworking;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.xxr.mom.ci.charging.interworking.base.InterfaceAccepter;
import com.xxr.mom.ci.charging.interworking.base.InterfaceSender;
import com.xxr.mom.ci.charging.interworking.dto.InterworkingConfigDto;
import com.xxr.mom.ci.charging.interworking.entity.InterworkingConfig;
import com.xxr.mom.ci.charging.interworking.entity.InterworkingNameMapping;
import com.xxr.mom.ci.charging.interworking.enums.VersionEnum;
import com.xxr.mom.ci.charging.service.InterworkingConfigService;
import com.xxr.mom.ci.common.dto.HlhtClientDto;
import com.xxr.mom.ci.common.dto.InterworkingParam;
import com.xxr.mom.ci.common.dto.InterworkingResult;
import com.xxr.mom.ci.common.enums.InterworkingRetEnum;
import com.xxr.mom.ci.common.exception.InterworkingException;
import com.xxr.mom.ci.common.util.Constant;
import com.xxr.mom.ci.common.util.EncryptionDecryptionUtil;
import com.xxr.mom.ci.common.util.JsonUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author natsuki_kining
 */
@Log4j2
@Service
public class ApiService {

    @Autowired
    private Map<String, InterfaceAccepter<?, ?>> accepterMap;
    @Autowired
    private Map<String, InterfaceSender<?, ?>> senderMap;
    @Autowired
    private InterworkingConfigService interworkingConfigService;

    /**
     * 验签
     * 根据OperatorID获取配置信息
     * 校验token
     * 解密报文，进行处理
     * 对处理结果进行加密返回
     * <p>
     * <p>
     * 充电接口调用流程，以客户端为例
     * 1、调用query_stations_info接口，拉取站点、充电桩、充电枪等数据
     * 2、根据充电枪等信息调用接口query_equip_business_policy，查询计费信息
     * 3、基础信息同步完成后，对接调我方接口notification_stationStatus，推送枪变化数据
     *
     * @param httpServletRequest HttpServletRequest
     * @param method             请求方法
     * @param interworkingParam  请求参数
     * @return
     */
    public InterworkingResult accept(HttpServletRequest httpServletRequest, String method, InterworkingParam interworkingParam) {
        InterworkingResult interworkingResult;
        log.info("请求方法:{}", method);
        log.info("请求参数:{}", JsonUtil.toJSONString(interworkingParam));
        try {
            InterworkingConfigDto configDto = this.accepterCheck(method, interworkingParam);
            InterfaceAccepter<?, ?> service = getAccepterService(httpServletRequest, method, interworkingParam, configDto);
            InterworkingConfig interworkingConfig = configDto.getInterworkingConfig();
            Object result = service.accept(interworkingParam, configDto);
            log.info("返回结果：{}", JsonUtil.toJSONString(result));
            String encryptResult = EncryptionDecryptionUtil.encrypt(interworkingConfig.getEncrypt(), JsonUtil.toJSONString(result));
            interworkingResult = InterworkingResult.success(interworkingConfig.getEncrypt(), encryptResult);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            interworkingResult = InterworkingResult.error(e);
        }
        log.debug("加密结果:{}", JsonUtil.toJSONString(interworkingResult));
        return interworkingResult;
    }

    private InterworkingConfigDto accepterCheck(String method, InterworkingParam interworkingParam) {
        // 校验参数是否为空
        if (interworkingParam.isEmpty()) {
            throw new InterworkingException(InterworkingRetEnum.PARAMETER_ERROR);
        }
        if (StringUtils.isBlank(interworkingParam.getData())) {
            throw new InterworkingException(InterworkingRetEnum.BUSINESS_PARAMETER_ERROR);
        }
        String regex = StrUtil.toCamelCase(method.toLowerCase()) + ".*" + Constant.ServiceSuffix.ACCEPTER_SERVICE;
        boolean parallel = accepterMap.keySet().stream().anyMatch(serviceName -> ReUtil.isMatch(regex, serviceName));
        if (!parallel) {
            throw new InterworkingException(InterworkingRetEnum.NOT_FOUND);
        }
        // 获取配置
        InterworkingConfigDto configDto = interworkingConfigService.getConfigDto(interworkingParam.getOperatorId());
        if (Objects.isNull(configDto)) {
            throw new InterworkingException(InterworkingRetEnum.PARAMETER_ERROR, "operatorId错误");
        }
        return configDto;
    }

    private InterfaceAccepter<?, ?> getAccepterService(HttpServletRequest httpServletRequest, String method, InterworkingParam interworkingParam, InterworkingConfigDto configDto) {
        InterworkingConfig interworkingConfig = configDto.getInterworkingConfig();
        String serviceName = StrUtil.toCamelCase(method.toLowerCase()) + VersionEnum.getServiceSuffix(interworkingConfig.getVersion()) + Constant.ServiceSuffix.ACCEPTER_SERVICE;
        // 如果存在方法名映射，则直接使用配置的映射
        List<InterworkingNameMapping> nameMappingList = configDto.getNameMappingList();
        if (CollectionUtil.isNotEmpty(nameMappingList)) {
            for (InterworkingNameMapping interworkingNameMapping : nameMappingList) {
                if (method.equals(interworkingNameMapping.getOperatorName())) {
                    serviceName = StrUtil.toCamelCase(interworkingNameMapping.getOwnerName());
                    break;
                }
            }
        }
        InterfaceAccepter<?, ?> service = accepterMap.get(serviceName);
        if (Objects.isNull(service)) {
            throw new InterworkingException(InterworkingRetEnum.NOT_FOUND);
        }
        service.validateSign(interworkingParam, configDto);
        service.validateToken(httpServletRequest.getHeader(interworkingConfig.getTokenName()), interworkingParam, configDto);
        return service;
    }

    public Object send(HlhtClientDto hlhtClientDto) {
        InterworkingConfigDto configDto = interworkingConfigService.getConfigDto(hlhtClientDto.getOperatorId());
        if (Objects.isNull(configDto)) {
            throw new InterworkingException(InterworkingRetEnum.PARAMETER_ERROR, "operatorId错误");
        }
        String serviceName = StrUtil.toCamelCase(hlhtClientDto.getMethod().toLowerCase()) + VersionEnum.getServiceSuffix(configDto.getInterworkingConfig().getVersion()) + Constant.ServiceSuffix.SENDER_SERVICE;
        InterfaceSender<?, ?> clientService = senderMap.get(serviceName);
        if (Objects.isNull(clientService)) {
            throw new InterworkingException(InterworkingRetEnum.NOT_FOUND);
        }
        return clientService.send(hlhtClientDto.getData(), configDto);
    }

}
